// 异常的执行过程

#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include <string>

class demo
{
private:
    std::string word;

public:
    demo(const std::string &str)
    {

        word = str;
        std::cout << "demo " << word << " created\n";
    }
    ~demo()
    {
        std::cout << "demo " << word << " destroyed\n";
    }
    void show() const
    {
        std::cout << "demo " << word << " lives!\n";
    }
};


class bad_hmean : std::exception
{
    public:
        const char * what(){ return "bad arguments to hmean() function!"};

};

class bad_gmean : std::exception
{
    public const char * what() { return "bad argumrnts to gmean() function!"}
}

// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
double means(double a, double b);

int main()
{
    using std::cin;
    using std::cout;
    using std::endl;

    double x, y, z;
    {
        demo d1("found in block in main()");
        cout << "Enter two numbers: ";
        while (cin >> x >> y)
        {
            try
            { // start of try block
                z = means(x, y);        // 进入means()
                cout << "The mean mean of " << x << " and " << y
                     << " is " << z << endl;
                cout << "Enter next pair: ";
            }                     // end of try block
            catch (bad_hmean &bg) // start of catch block
            {
                bg.mesg();
                cout << "Try again.\n";
                continue;
            }
            catch (bad_gmean &hg)
            {
                cout << hg.mesg();
                cout << "Values used: " << hg.v1 << ", "
                     << hg.v2 << endl;
                cout << "Sorry, you don't get to play any more.\n";
                break;
            } // end of catch block
            catch (...)
            {
                exit(EXIT_FAILURE);
            }
        }
        d1.show();
    }
    cout << "Bye!\n";
    // cin.get();
    // cin.get();
    return 0;
}

double hmean(double a, double b)
{
    if (a == -b)
    throw bad_hmean(a, b);      // 这里的throw语句理解为跳转,跳转到进入这个语句的上层try语句块的末尾
    return 2.0 * a * b / (a + b);
}

double gmean(double a, double b)
{
    if (a < 0 || b < 0)
        throw bad_gmean(a, b);
    return std::sqrt(a * b);
}

double means(double a, double b)
{
    double am, hm, gm;
    demo d2("found in means()");
    am = (a + b) / 2.0; // arithmetic mean
    try     // 分别判定hmean()和gmea是否发生异常
    {
        hm = hmean(a, b);       // 如果这里出现异常,那么将会通过throw关键字创建一个/临时/bad_hmean对象并向上抛出
        gm = gmean(a, b);
        // 程序函数提前终止的情况下,会有一步栈解退的操作,释放栈中的自动变量或者释放对象(调用对象的析构函数)
    }
    catch (bad_hmean &bg) // 代码中使用引用进行接收Exception对象是因为可以使用这样的技巧使用 Exception类对象的派生类对象
    {
        bg.mesg();
        std::cout << "Caught in means()\n";
        throw; // rethrows the exception
        // 如果没有指定throw的内容,则向上一个调用他的函数抛出,并进行栈解退
    }
    d2.show();
    return (am + hm + gm) / 3.0;
}

// 如果这里有一个类似与这样的异常类型声明:
class bad_class1 : public std::exception {/* ... */};
class bad_class2 : public bad_class2 {/* ... */};
class bad_class3 : public bad_class3 {/* ... */};
class bad_class4 : public bad_class4 {/* ... */};

try
{
    /* code */
}
catch(bad_class4 & e){
    /* ... */
}
catch (bad_class3 &e)
{
    /* ... */
}
catch (bad_class2 &e)
{
    /* ... */
}
catch (bad_class1 &e)
{
    /* ... */
}
catch(const std::exception& e)
{
    std::cerr << e.what() << '\n';
}

//  virtual const char* what() const
// exception类中定义了一个what()函数,返回一个字符串类型,用于追踪错误对象